﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text;
using chore.Domain;
using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using NHibernate;
using NHibernate.Linq;

namespace chore.Services
{
    public abstract class ServiceBase
    {
        public ISession Session
        {
            get { return Database.SessionFactory.OpenSession(); }
        }
    }

    public class Translator
    {
        public static AssignmentDTO DTOFromAssignment(Assignment assignment)
        {
            return new AssignmentDTO()
            {
                Id = assignment.Id,
                Completed = assignment.Completed,
                CompletedBy = assignment.CompletedBy.Name,
                CompletedById = assignment.CompletedBy.Id,
                AssignedTo = assignment.AssignedTo.Name,
                AssignedToId = assignment.AssignedTo.Id,
                Started = assignment.Starting,
                Helpers = assignment.WithHelpFrom.Select(h => SimpleDTOFromUser(h)).ToList()
            };
        }

        public static SimpleAssignmentDTO SimpleDTOFromAssignment(Assignment assignment)
        {
            return new SimpleAssignmentDTO()
                       {
                           Id = assignment.Id,
                           Completed = assignment.Completed,
                           CompletedBy = assignment.CompletedBy.Name,
                           CompletedById = assignment.CompletedBy.Id,
                           AssignedTo = assignment.AssignedTo.Name,
                           AssignedToId = assignment.AssignedTo.Id,
                           TimeElapsed = assignment.TimeElapsed,
                           Started = assignment.Starting
                       };
        }

        public static Assignment FromAssignmentDTO(AssignmentDTO assignment)
        {
            return new Assignment()
                       {
                           Id = assignment.Id,
                           Completed = assignment.Completed,
                           Frequency = assignment.TimeElapsed,
                           Starting = assignment.Started,
                       };
        }

        public static Assignment FromSimpleAssignmentDTO(SimpleAssignmentDTO assignment)
        {
            return new Assignment()
            {
                Id = assignment.Id,
                Completed = assignment.Completed,
                Frequency = assignment.TimeElapsed,
                Starting = assignment.Started,
                AssignedTo = new User() {Id = assignment.AssignedToId, Name = assignment.AssignedTo},
                CompletedBy = new User() {Id = assignment.CompletedById, Name = assignment.CompletedBy},
                TimeElapsed = assignment.TimeElapsed
            };
        }

        public static ChoreDTO DTOFromChore(Chore chore)
        {
            return new ChoreDTO()
            {
                Id = chore.Id,
                Description = chore.Description,
                OwnedBy = chore.Owner.Name,
                OwnerId = chore.Owner.Id,
                Title = chore.Title,
                Assignments = chore.Assignments.Select(a => SimpleDTOFromAssignment(a)).ToList()
            };
        }

        public static SimpleChoreDTO SimpleDTOFromChore(Chore chore)
        {
            return new SimpleChoreDTO()
                       {
                           Id = chore.Id,
                           Description = chore.Description,
                           OwnedBy = chore.Owner.Name,
                           OwnerId = chore.Owner.Id,
                           Title = chore.Title
                       };
        }

        public static Chore FromChoreDTO(ChoreDTO chore)
        {
            return new Chore()
                       {
                           Id = chore.Id,
                           Title = chore.Title,
                           Description = chore.Description,
                           Assignments = chore.Assignments.Select(a => FromSimpleAssignmentDTO(a)).ToList()
                       };
        }

        public static Chore FromSimpleChoreDTO(SimpleChoreDTO chore)
        {
            return new Chore()
                       {
                           Id = chore.Id,
                           Title = chore.Title,
                           Description = chore.Description,
                       };
        }

        public static User UserFromDTO(UserDTO user)
        {
            return new User()
                       {
                           Id = user.Id,
                           Name = user.Name,
                           Assignments = user.Assignments.Select(a => FromSimpleAssignmentDTO(a)).ToList(),
                           Chores = user.Chores.Select(c => FromSimpleChoreDTO(c)).ToList()
                       };
        }

        public static User UserFromSimpleDTO(SimpleUserDTO user)
        {
            return new User()
            {
                Id = user.Id,
                Name = user.Name
            };
        }

        public static UserDTO DTOFromUser(User user)
        {
            return new UserDTO()
            {
                Id = user.Id,
                Name = user.Name,
                Assignments = user.Assignments.Select(a => SimpleDTOFromAssignment(a)).ToList(),
                Chores = user.Chores.Select(c => SimpleDTOFromChore(c)).ToList()
            };
        }

        public static SimpleUserDTO SimpleDTOFromUser(User user)
        {
            return new SimpleUserDTO()
            {
                Id = user.Id,
                Name = user.Name
            };
        }
    }

    public class ChoreService : ServiceBase
    {
        public IEnumerable<SimpleChoreDTO> GetChores()
        {
            using(var session = Session)
            {
                return
                    from chore in session.Linq<Chore>()
                    select Translator.SimpleDTOFromChore(chore);
            }
        }

        public void AddChore(ChoreDTO chore)
        {
            using (var session = Session)
            {
                session.Save(Translator.FromChoreDTO(chore));
            }
        }

        public void UpdateChore(ChoreDTO chore)
        {
            using (var session = Session)
            {
                session.Update(Translator.FromChoreDTO(chore));
            }
        }

        public void DeleteChore(ChoreDTO chore)
        {
            using (var session = Session)
            {
                session.Delete(Translator.FromChoreDTO(chore));
            }
        }
    }

    public class Database
    {
        private static ISessionFactory _factory = null;
        public static ISessionFactory SessionFactory
        {
            get
            {
                _factory = _factory ?? Fluently
                    .Configure()
                    .Database(MsSqlConfiguration.MsSql2008.ConnectionString(ConfigurationManager.ConnectionStrings["chores"].ConnectionString))
                    .Mappings(m => m.FluentMappings.AddFromAssemblyOf<Chore>())
                    .BuildSessionFactory();

                return _factory;
            }
        }
    }

    public class ChoreDTO
    {
        public long Id { get; set; }
        public string Title { get; set; }
        public string Description { get; set; }
        public string OwnedBy { get; internal set; }
        public long OwnerId { get; set; }
        public List<SimpleAssignmentDTO> Assignments { get; set; }
    }

    public class SimpleChoreDTO
    {
        public long Id { get; set; }
        public string Title { get; set; }
        public string Description { get; set; }
        public string OwnedBy { get; internal set; }
        public long OwnerId { get; set; }
    }

    public class AssignmentDTO
    {
        public long Id { get; set; }
        public bool Completed { get; set; }
        public long CompletedById { get; set; }
        public string CompletedBy { get; internal set; }
        public long AssignedToId { get; set; }
        public string AssignedTo { get; internal set; }
        public TimeSpan TimeElapsed { get; set; }
        public DateTime Started { get; set; }
        public double MinutesElapsed
        {
            get { return TimeElapsed.TotalMinutes; }
            set { TimeElapsed = TimeSpan.FromMinutes(value); }
        }
        public List<SimpleUserDTO> Helpers { get; set; }
    }

    public class SimpleAssignmentDTO
    {
        public long Id { get; set; }
        public bool Completed { get; set; }
        public long CompletedById { get; set; }
        public string CompletedBy { get; internal set; }
        public long AssignedToId { get; set; }
        public string AssignedTo { get; internal set; }
        public TimeSpan TimeElapsed { get; set; }
        public DateTime Started { get; set; }
        public double MinutesElapsed
        {
            get { return TimeElapsed.TotalMinutes; }
            set { TimeElapsed = TimeSpan.FromMinutes(value); }
        }
    }

    public class SimpleUserDTO
    {
        public long Id { get; set; }
        public string Name { get; set; }
    }

    public class UserDTO
    {
        public long Id { get; set; }
        public string Name { get; set; }
        public List<SimpleAssignmentDTO> Assignments { get; set; }
        public List<SimpleChoreDTO> Chores { get; set; }
    }
}
